#include "Ast.h"
#include "Imm.h"
#include "ParserUtil.h"
#include "AbsMachCode.h"
#define TEST_SUPREET
#define CINFO	yylinenum, yycolumnno, yyfilename

/****************************************************************/
const OpNode::OpInfo OpNode::opInfo[] = {
	// print name, arity, paren_flag, fixity, arg types, out type, constraints
	//
	// Paren_flag -- opnode->print() outputs is surrounded by parenthesis if
	// this flag is set. As set below, the expression may not print correctly
	// in some rare cases, e.g., ~(b * c) will get printed as ~b * c,
	// which actually corresponds to (~b)*c. To ensure that things get printed
	// correctly all the time, more paren_flags should be set to 1, but this
	// will lead to more clutter in printed output. Basically, what we have done
	// here is to look are expressions by type -- arithmetic, relational,
	// boolean, bit operations, etc. Within each type, the highest priority
	// operator is printed without paren. This will work correctly, as long
	// as the language doesn't permit mixing of different types of expressions.
	// But this assumption doesn't always hold, as in the example above. Also,
	// there is an exception to this general approach in the case of unary minus
	// and * -- since (-a)*b and -(a*b) have the same meaning, we can exclude
	// paren for * without an error.
	//
	// Codes for constraints:
	// first character:
	//    N: No additional constraint over what is given by argTypes
	//    I: all arguments must have identical type
	//    S: one of the arguments must have a type that is a supertype of
	//        of all other arguments. All other arguments require a coercion
	//        operation to be introduced so as to convert their type to S.
	//    s: one of the arguments must have a type that is a subtype of
	//        of all other arguments.
	//    L: all list arguments (and list output) must have same type. In
	//        addition, all non-list arguments (and output) must have same
	//        type as that of elements in these lists
	//    T: all tuple arguments to the function must have same type.
	//    A: (assignment). Type of second argument must be a subtype of
	//       the first argument
	//
	// second character:
	//    O: output type is the same as out type. (In the following cases,
	//        the output type need not be equal to out type, but a subtype
	//        of it.) Since a TypeTag provides complete type information only
	//        for primitive types, `O' is applicable only in this case.
	//    digit: output type is the same as that of the digit'th argument
	//       In this case, a third character may be used, the code for
	//       which is as follows:
	//         'e' denotes that the output is of type alpha, where
	//             the type of digit'th argument is list(alpha)
	//         'l' denotes that the output is of type list(alpha), where
	//             alpha is the type of the digit'th argument.
	//    S: The output type is the same as that of the argument with the
	//        most general type. (Typically used with first character 'S')
	//    s: The output type is the same as that of the argument with the
	//        least general type. (Typically used with first character 'S')
	//    P: The output type is the product of the types of all arguments
	//    p: The output type is a component of the input tuple type. The
	//        following character specifies the component. A digit k specifies
	//        that the component number as k. The character 'a' indicates that
	//        the component number is given by an integer argument to the
	//        operator. The argument number is given by the following digit.
	//        'p' can be used only in conjunction with first character 'P'.
	//    L: Output type is the same as type of list arguments. Can be used
	//        only in conjunction with first character L.
	//    e: Output type is the same as type of element of list arguments.
	//        Can be used only in conjunction with first character L.
	//
	{OpNode::UMINUS, "-",  1, 0, OpNode::PREFIX, {Type::SIGNED}, Type::SIGNED, "N1"},
	{OpNode::PLUS, "+",  2, 1, OpNode::INFIX, {Type::NUMERIC, Type::NUMERIC}, Type::NUMERIC, "SS"},
	{OpNode::MINUS, "-",  2, 1, OpNode::INFIX, {Type::NUMERIC, Type::NUMERIC}, Type::NUMERIC, "SS"},
	{OpNode::MULT, "*",  2, 0, OpNode::INFIX, {Type::NUMERIC, Type::NUMERIC}, Type::NUMERIC, "SS"},
	{OpNode::DIV, "/",  2, 1, OpNode::INFIX, {Type::NUMERIC, Type::NUMERIC}, Type::NUMERIC, "SS"},
	{OpNode::MOD, "%",  2, 1, OpNode::INFIX, {Type::INTEGRAL, Type::INTEGRAL}, Type::INTEGRAL, "S2"},
	{OpNode::EQ, "==", 2, 0, OpNode::INFIX, {Type::PRIMITIVE, Type::PRIMITIVE}, Type::BOOL, "SO"},
	{OpNode::NE, "!=", 2, 0, OpNode::INFIX, {Type::PRIMITIVE, Type::PRIMITIVE}, Type::BOOL, "SO"},
	{OpNode::GT, ">",  2, 0, OpNode::INFIX, {Type::SCALAR, Type::SCALAR}, Type::BOOL, "SO"},
	{OpNode::LT, "<",  2, 0, OpNode::INFIX, {Type::SCALAR, Type::SCALAR}, Type::BOOL, "SO"},
	{OpNode::GE, ">=", 2, 0, OpNode::INFIX, {Type::SCALAR, Type::SCALAR}, Type::BOOL, "SO"},
	{OpNode::LE, "<=", 2, 0, OpNode::INFIX, {Type::SCALAR, Type::SCALAR}, Type::BOOL, "SO"},
	{OpNode::AND, "&&",  2, 1, OpNode::INFIX, {Type::BOOL, Type::BOOL}, Type::BOOL, "NO"},
	{OpNode::OR, "||",  2, 1, OpNode::INFIX, {Type::BOOL, Type::BOOL}, Type::BOOL, "NO"},
	{OpNode::NOT, "!",  1, 0, OpNode::PREFIX, {Type::BOOL}, Type::BOOL, "NO"},
	{OpNode::BITNOT, "~",  1, 0, OpNode::PREFIX, {Type::INTEGRAL}, Type::INTEGRAL, "N1"},
	{OpNode::BITAND, "&",  2, 1, OpNode::INFIX, {Type::INTEGRAL, Type::INTEGRAL}, Type::INTEGRAL, "Ss"},
	{OpNode::BITOR, "|",  2, 1, OpNode::INFIX, {Type::INTEGRAL, Type::INTEGRAL}, Type::INTEGRAL, "SS"},
	{OpNode::BITXOR, "^",  2, 0, OpNode::INFIX, {Type::INTEGRAL, Type::INTEGRAL}, Type::INTEGRAL, "SS"},
	{OpNode::SHL, "<<", 2, 1, OpNode::INFIX, {Type::INTEGRAL, Type::INTEGRAL}, Type::INTEGRAL, "N1"},
	{OpNode::SHR, ">>", 2, 1, OpNode::INFIX, {Type::INTEGRAL, Type::INTEGRAL}, Type::INTEGRAL, "N1"},
	{OpNode::ASSIGN, "=",  2, 0, OpNode::INFIX, {Type::NATIVE, Type::NATIVE}, Type::VOID, "AO"},
	{OpNode::PRINT, "print", OpNode::VARIABLE, 1, OpNode::PREFIX, {Type::NATIVE}, Type::VOID, "NO"},
	{OpNode::INVALID, "invalid",            0, 0, OpNode::PREFIX, {}, Type::ERROR, "NO"}
};

string OpNode::OpCodeStr(OpCode code) {
	switch(code) {
    case UMINUS:
	case PLUS:
	case MINUS:
	case MULT:
	case DIV:
	case MOD:
	case EQ:
		return "EQ";
	case NE:
		return "NE";
	case GT:
		return "GT";
	case LT:
		return "LT";
	case GE:
		return "GE";
	case LE:
		return "LE";
	case AND:
	case OR:
	case NOT:
    case BITNOT:
	case BITAND:
	case BITOR:
	case BITXOR:
	case SHL:
	case SHR:
    case ASSIGN:
	case PRINT:
	case INVALID:
		break;
	};
	return "";
}

OpNode::OpNode(OpCode op, ExprNode* a1, ExprNode* a2,
		int ln, int col, string file):
	ExprNode(ExprNode::OP_NODE, NULL, ln,col,file) {
		opCode_ = op;
		if (a1 != NULL) {
			arity_ = 1;
			arg_.push_back(a1);
			if (a2 != NULL) {
				arity_++;
				arg_.push_back(a2);
			}
		}
	}

OpNode::OpNode(const OpNode &other):
	ExprNode(other) {
		arity_ = other.arity();
		opCode_ = other.opCode();
		for (unsigned int i=0; (i < other.arity()); i++) {
			if (other.arg_[i]) {
				arg_.push_back((other.arg_[i])->clone());
			}
			else {
				arg_.push_back(NULL);
			}
		}
	}

void
OpNode::print(ostream& os, int indent) const {
	if (opInfo[opCode_].prtType_ == OpNode::PREFIX) {
		os << opInfo[opCode_].name_;
		if (arity_ > 0) {
			if (opInfo[opCode_].needParen_)
				os << '(';
			for (unsigned i=0; i < arity_-1; i++) {
				if (arg_[i])
					arg_[i]->print(os, indent);
				else os << "NULL";
				os << ", ";
			}
			if (arg_[arity_-1])
				arg_[arity_-1]->print(os, indent);
			else os << "NULL";
			if (opInfo[opCode_].needParen_)
				os << ") ";
		}
	}
	else if ((opInfo[opCode_].prtType_ == OpNode::INFIX) && (arity_ == 2)) {
		if (opInfo[opCode_].needParen_)
			os << "(";
		if(arg_[0])
			arg_[0]->print(os, indent);
		else os << "NULL";
		os << opInfo[opCode_].name_;
		if(arg_[1])
			arg_[1]->print(os, indent);
		else os << "NULL";
		if (opInfo[opCode_].needParen_)
			os << ")";
	}
	else internalErr("Unhandled case in OpNnode::print");
}

#define EXPR_1ARG()	{c->add(arg_[0]->code(controlFlow));	\
					c->add(ImmCode::EXPR, addr(), arg_[0]->addr(), NULL, opCode_);}
#define EXPR_2ARG() {c->add(arg_[0]->code(controlFlow)); \
					c->add(arg_[1]->code(controlFlow)); \
					c->add(ImmCode::EXPR, addr(), arg_[0]->addr(),\
					arg_[1]->addr(), opCode_);}

ImmCodes* OpNode::code(bool controlFlow) {
	ImmCodes* c = new ImmCodes();
	switch(opCode_) {
		case UMINUS:
			c->add(arg_[0]->code(controlFlow));
			c->add(ImmCode::EXPR, addr(), arg_[0]->addr(),
				new ValueNode(new Value(-1,Type::INT)), MULT);
		break;
		case NOT:
			if (controlFlow) {
				arg_[0]->True(False());
				arg_[0]->False(True());
				c->add(arg_[0]->code(true));
			} else {
				EXPR_1ARG();
			}
		break;
		case BITNOT:
			EXPR_1ARG();
		break;
   		case PLUS:
		case MINUS:
		case MULT:
		case DIV:
		case MOD:
		case BITAND:
		case BITOR:
		case BITXOR:
		case SHL:
		case SHR:
			EXPR_2ARG();
			break;
		case EQ:
		case NE:
		case GT:
		case LT:
		case GE:
		case LE:
			if (controlFlow) {
				c->add(arg_[0]->code());
				c->add(arg_[1]->code());
				c->add(ImmCode::IF_REL,True(),arg_[0]->addr(),
					arg_[1]->addr(),opCode_);
				c->add(ImmCode::GOTO,False());
			} else
				EXPR_2ARG();
			break;
		case AND:
			if (controlFlow) {
				arg_[0]->True(c->newLabel());
				arg_[0]->False(False());
				arg_[1]->True(True());
				arg_[1]->False(False());
				c->add(arg_[0]->code(true));
				c->add(arg_[0]->True());
				c->add(arg_[1]->code(true));
			} else
				EXPR_2ARG();
			break;
		case OR:
			if (controlFlow) {
				arg_[0]->True(True());
				arg_[0]->False(c->newLabel());
				arg_[1]->True(True());
				arg_[1]->False(False());
				c->add(arg_[0]->code(true));
				c->add(arg_[0]->False());
				c->add(arg_[1]->code(true));
			} else
				EXPR_2ARG();
			break;
		case ASSIGN:
			c->add(arg_[1]->code(controlFlow));
			c->add(ImmCode::EXPR, arg_[0]->addr(),arg_[1]->addr(),NULL, opCode_);
			break;
		case PRINT:
			EXPR_1ARG();
			break;
		case INVALID:
		break;
	};
	return c;
}

// AstNode implemenation
AstNode::AstNode(NodeType nt, int line, int column, string file) :
	ProgramElem(NULL, line, column, file) {
	addr_ = NULL;
}
AstNode::AstNode(const AstNode& node) { // copy constructor
	nodeType_ = node.nodeType_;
}

ExprNode* ExprNode::addr() {
	if (addr_==NULL) {
		addr_=new TempNode();
		// type
		addr_->type((Type*)coercedType());
		if (addr_->type()==NULL)
			addr_->type(type());
	}
	return (ExprNode*)addr_;
}

// ExprNode implementation
ExprNode::ExprNode(ExprNodeType et, const Value* val, int line, int column,
		string file) : AstNode(EXPR_NODE, line, column, file) {
	val_ = val;
	exprType_ = et;
	coercedType_ = NULL;
}

ExprNode::ExprNode(const ExprNode& node) : AstNode(node) {
	val_ = node.val_;
	coercedType_ = node.coercedType_;
}

// TempNode impl.
TempNode::TempNode(int line, int column, string file)
  : ExprNode(ExprNode::TEMP_NODE, NULL, line,column,file) {
	name_ = newName("t");
	// Duckjin-Leave it empty, we can't figure out
	//	the name of register before knowing the type
	//reg_name = newRegister();
	addr_ = this;
}

string TempNode::registerName() {
	if (reg_name.length()!=0) return reg_name;
	const Type* typ = coercedType();
	if (typ==NULL) typ=type();
	// Figure out register name
	if (typ && typ->isFloat(typ->tag())) {
		// Allocate float register
		registerName(newRegister(true));
	} else {
		// Allocate integer register
		registerName(newRegister(false));
	}
	return reg_name;
}

void TempNode::print(ostream& os, int indent) const {

}
// RefExprNode impl.
RefExprNode::RefExprNode(string ext, const SymTabEntry* ste,
		int line, int column, string file) :
			ExprNode(REF_EXPR_NODE, 0, CINFO) {
	ext_ = ext;
	// Duckjin-Leave it empty, we can't figure out
	//	the name of register before knowing the type
	//reg_name = newRegister();
	sym_ = ste;
	type((Type*)ste->type());
	addr_ = this;
}

string RefExprNode::registerName() {
	return ((SymTabEntry*)sym_)->registerName();
}

RefExprNode::RefExprNode(const RefExprNode& node) :
		ExprNode(REF_EXPR_NODE, 0, node.line(), node.column(), node.file()) {
	ext_ = node.ext_;
	// Duckjin-Leave it empty, we can't figure out
	//	the name of register before knowing the type
	//reg_name = newRegister();
	sym_ = node.sym_;
	type((Type*)sym_->type());
	addr_ = this;
}

void RefExprNode::print(ostream &os, int indent) const {
	os << ext();
}

ImmCodes* RefExprNode::code(bool controlFlow) {
	if (!controlFlow) return NULL;
	ImmCodes* c = new ImmCodes();
	c->add(ImmCode::IF, True(), this);
	c->add(ImmCode::GOTO, False());
	return c;
}

// ValueNode
void ValueNode::print(ostream& os, int indent) const {
	value()->print(os,indent);
}
ImmCodes* ValueNode::code(bool controlFlow) {
	if (controlFlow) {
		ImmCodes* c = new ImmCodes();
		if (value()->ival() || value()->bval() || value()->dval())
			c->add(ImmCode::GOTO, (void*)True());
		else
			c->add(ImmCode::GOTO, (void*)False());
		return c;
	}
	return NULL;
}

// PrimitivePatNode
PrimitivePatNode::PrimitivePatNode(EventEntry* ee, vector<VariableEntry*>* params,
		ExprNode* c,int line, int column, string file) :
		BasePatNode(PRIMITIVE, CINFO)
{
	ee_ = ee;
	cond_ = c;
	params_ = params;
    int formal_arg=0;
    int i=0,j=0;
	// copy event type to variable type
    if(params !=NULL && ee != NULL) {
    vector<VariableEntry*> ve = *params;
    vector<Type*> te ;
    if(ee->type())
    te = *(ee->type()->argTypes());
        //if(ve.size() > 0 && te.size() > 0) {
            for (i=0,j=0; i< te.size(),j<ve.size(); i++,j++) {
                if (ve[j]!=NULL)
                    ve[j]-> type(te[i]);
            }
        //}
        if(te.size() < ve.size()) {
                for (i=te.size();i<ve.size(); i++) {
                if (ve[i]!=NULL)
                    ve[i]-> type((Type *)NULL);
            }
        }
    }

	if (params) {
		vector<VariableEntry*>::iterator it = params->begin();
		for (;it!=params->end();it++) {
			if (stm.lookUpInScope((*it)->name(), SymTabEntry::BLOCK_KIND)) {
				string _err = "Redefinition of name ";
				_err += (*it)->name();
				errMsg(_err);
			} else
				stm.insert((*it));
		}
	}
	if (ee_ && params_) {
	    Type* type = ee_->type();
		vector<Type*>* argTypes = NULL;
		if (type) argTypes = type->argTypes();
		if (argTypes)
		formal_arg = argTypes->size();
		else
		formal_arg = 0;
		/*if (argTypes && params_->size() > argTypes->size()) {
			string _err = ee_->name();
			_err += ": mismatch in the number of arguments";
			errMsg(_err);
		}*/
		#ifndef TEST_TYPE
		if (params_->size() > formal_arg) {
			string _err = ee_->name();
			_err += ": mismatch in the number of arguments";
			errMsg(_err);
		}
		#endif
	}
}

void PrimitivePatNode::print(ostream& os, int indent) const {
	if (!ee_) return;
	Type* type = ee_->type();
	vector<Type*>* argTypes = NULL;
	if (type) argTypes = type->argTypes();

	os << "(" << ee_->name();
	#ifndef TEST_EVENTMAT
	if (params_) {
		os << "(";
		vector<VariableEntry*>::const_iterator it;
		vector<Type*>::const_iterator itType;
		for (it = params_->begin(),itType = argTypes->begin();it!=params_->end();) {
			if ((*itType) && (*it))
				os << (*itType)->fullName() << " " <<  (*it)->name();
			++it;
			++itType;
			if (it!=params_->end() && itType!=argTypes->end())
				os << ", ";
		}
		os << ")";
	} else {
		if (ee_->name()!="any")
			os << "()";
	}
	if (cond_) {
		os << "|";
		cond_->print(os,indent);
	}
	#endif
	os << ")";

}

bool PrimitivePatNode::hasSeqOps() const {
	return false;
}
bool PrimitivePatNode::hasNeg() const {
	return false;
}
bool PrimitivePatNode::hasAnyOrOther() const {
	//return false;
	if(event() == NULL)
        return false;
    if(event()->name() == "any")
      return true;

    return false;
}

//ExprStmtNode
ImmCodes* ExprStmtNode::code(bool controlFlow) {
	ImmCodes* c = new ImmCodes();
	c->add(expr_->code(controlFlow));
	return c;
}

// ReturnStmtNode
ImmCodes* ReturnStmtNode::code(bool controlFlow) {
	ImmCodes* c= new ImmCodes();
	if (expr_) {
		c->add(expr_->code(controlFlow));
		c->add(ImmCode::LEAVE, expr_->addr(), (void*)fun_);
	} else {
		c->add(ImmCode::LEAVE, NULL, (void*)fun_);
	}
	return c;
}

// CompoundStmtNode
ImmCodes* CompoundStmtNode::code(bool controlFlow) {
	if (stmts_ == NULL) return NULL;
	ImmCodes* c = new ImmCodes();
	list<StmtNode*>* sm = stmts_;
	list<StmtNode*>::iterator it = sm->begin();
	for (;it!=sm->end();it++) {
		/* propagate Next */
		(*it)->Next(Next());
		c->add((*it)->code(controlFlow));
	}
	return c;
}

bool CompoundStmtNode::isLastStatementReturn() {
	StmtNode* last = stmts_->back();
	if (last && last->stmtNodeKind() == StmtNode::RETURN) return true;
	return false;
}

void CompoundStmtNode::printWithoutBraces(ostream& os, int indent) const {
	if (stmts_ == NULL) return;
	list<StmtNode*>* sm = stmts_;
	list<StmtNode*>::iterator it = sm->begin();
	while(1) {
		if (*it) {
			(*it)->print(os,indent);
			if ( (*it)->stmtNodeKind() == StmtNode::EXPR || (*it)->stmtNodeKind() == StmtNode::RETURN ) {
				os << ";";
				++it;
				if ( it == sm->end() )
					prtln(os,indent-STEP_INDENT);
				else
					prtln(os,indent);
				--it;
			}
			it++;
			if (it==sm->end())
				break;
		} else {
			break;
		}
	};
}
void CompoundStmtNode::print(ostream& os, int indent) const {
	os << "{";
	if (stmts_ && stmts_->size()) {
		prtln(os,indent+STEP_INDENT);
		printWithoutBraces(os,indent+STEP_INDENT);
	}
	os << "};";
	prtln(os,indent);
}


BasePatNode*
PrimitivePatNode::derivativeWRTname(string eventName) const{
	  if (event() && event()->name() == eventName){
		  return new PatNode(BasePatNode::EMPTY, (BasePatNode*)NULL);
	  }
	  else
		  return new PatNode(BasePatNode::UNDEFINED, (BasePatNode*)NULL);
  }

vector<BasePatNode*>*
PrimitivePatNode::getNextItemSet(string eventName) const {
	  vector<BasePatNode*>* result = new vector<BasePatNode*>();
	  if (event() && event()->name() == eventName){
		  result->push_back(new PatNode(BasePatNode::EMPTY, (BasePatNode*)NULL));
	  }
	  else
		  result->push_back(new PatNode(BasePatNode::UNDEFINED, (BasePatNode*)NULL));
	  return result;
};

// PatNode
PatNode::PatNode(int line, int column, string file) : BasePatNode(UNDEFINED, CINFO) {
}

PatNode::PatNode(PatNodeKind pk, BasePatNode *p1, BasePatNode*p2, int line, int column, string file) : BasePatNode(pk, CINFO) {

	pat1_ = p1;
	pat2_ = p2;

	//#ifdef TEST_AST
	/*if (pk == NEG && pat1_ &&
		( pat1_->hasNeg() || pat1_->kind() != BasePatNode::PRIMITIVE )) {
		string err_ = "Only simple patterns without `.', `*', and `!' operatorscan be negated";
		errMsg(err_);
	}*/


	//#endif

	//PRIMITIVE, EMPTY, NEG, SEQ, OR, STAR, UNDEFINED

/*


	if (pk == BasePatNode::OR){
		if (pat2_ && pat2_->kind() == BasePatNode::UNDEFINED)
		{
			kind(BasePatNode::PRIMITIVE);
			pat2_ = NULL;

			if (pat1_ && pat1_->kind() == BasePatNode::UNDEFINED)
			{
				kind(BasePatNode::UNDEFINED);
				pat1_ = NULL;
			}

		}
		else if (pat1_ && pat1_->kind() == BasePatNode::UNDEFINED)
		{
			kind(BasePatNode::PRIMITIVE);
			pat1_ = pat2_;
			pat2_ = NULL;
		}
		else if (pat1_ && pat1_->kind() == BasePatNode::EMPTY){
			kind(BasePatNode::PRIMITIVE);
			pat1_ = pat2_;
			pat2_ = NULL;
			if (pat1_ && pat1_->kind() == BasePatNode::EMPTY)
			{
				kind(BasePatNode::EMPTY);
				pat1_ = NULL;
			}
		}
		else if (pat2_ && pat2_->kind() == BasePatNode::EMPTY){
			kind(BasePatNode::PRIMITIVE);
			pat2_ = NULL;
		}


	}
	else if (pk == BasePatNode::SEQ){
		if ((pat1_ && pat1_->kind() == BasePatNode::UNDEFINED) || (pat2_ && pat2_->kind() == BasePatNode::UNDEFINED))
		{
			kind(BasePatNode::UNDEFINED);
			pat1_ = NULL;
			pat2_ = NULL;
		}
		else if (pat2_ && pat2_->kind() == BasePatNode::EMPTY && pat1_ && pat1_->kind() != BasePatNode::EMPTY){
			kind(BasePatNode::PRIMITIVE);
			pat2_ = NULL;
		}
		else if (pat1_ && pat1_->kind() == BasePatNode::EMPTY && pat2_ && pat2_->kind() != BasePatNode::EMPTY){
			kind(BasePatNode::PRIMITIVE);
			pat1_ = pat2_;
			pat2_ = NULL;
		}
		else if (pat1_ && pat1_->kind() == BasePatNode::EMPTY && pat2_ && pat2_->kind() == BasePatNode::EMPTY){
			kind(BasePatNode::EMPTY);
			pat1_ = NULL;
			pat2_ = NULL;
		}

	}


/*	if (pk == BasePatNode::OR){
		if ((pat1_ == NULL || pat1_->kind() == BasePatNode::UNDEFINED) && pat2_ && pat2_->kind() != BasePatNode::UNDEFINED){
			kind(BasePatNode::PRIMITIVE);
			pat1_ = pat2_;
			pat2_ = NULL;
		}
		else if ((pat2_ == NULL || pat2_->kind() == BasePatNode::UNDEFINED)
				&& pat1_ && pat1_->kind() != BasePatNode::UNDEFINED	){
			kind(BasePatNode::PRIMITIVE);
			pat2_ = NULL;
		}

	}


	/*

	if ((pat1_ == NULL || pat1_->kind() == BasePatNode::UNDEFINED) && pat2_ && pat2_->kind() != BasePatNode::UNDEFINED){
		kind(BasePatNode::PRIMITIVE);
		pat1_ = pat2_;
		pat2_ = NULL;
	}
	else if ((pat2_ == NULL || pat2_->kind() == BasePatNode::UNDEFINED)
			&& pat1_ && pat1_->kind() != BasePatNode::UNDEFINED
			&& pat1_->kind() != BasePatNode::STAR
			){
		kind(BasePatNode::PRIMITIVE);
		pat2_ = NULL;
	}
/*	else if ((pat1_ == NULL || pat1_->kind() == BasePatNode::UNDEFINED) && (pat2_ == NULL || pat2_->kind() == BasePatNode::UNDEFINED))
	{
		kind(BasePatNode::UNDEFINED);
		pat1_ = NULL;
		pat2_ = NULL;
	}
*/

}

bool PatNode::hasNeg() const {
	if ( (pat1_ || pat2_) && kind() == NEG)
		return true;
	if (pat1_ && pat1_->hasNeg()) return true;
	if (pat2_ && pat2_->hasNeg()) return true;
	return false;
}
bool PatNode::hasSeqOps() const {
	if ( (pat1_ && pat2_) && kind() == SEQ)
		return true;
    /* added by supreet */
    if ( (pat1_ || pat2_) && kind() == STAR)
		return true;
    /* added bt supreet */
	if (pat1_ && pat1_->hasSeqOps()) return true;
	if (pat2_ && pat2_->hasSeqOps()) return true;
	return false;
}
bool PatNode::hasAnyOrOther() const {
	/*if ( (pat1_ && pat2_) && kind() == OR)
		return true;
	if (pat1_ && pat1_->kind()!=PRIMITIVE) return true;
	if (pat2_ && pat2_->kind()!=PRIMITIVE) return true;
	return false;*/
	//if ( kind() !=PRIMITIVE)
		//return false;
	if (pat1_ && pat1_->hasAnyOrOther()) return true;
	if (pat2_ && pat2_->hasAnyOrOther()) return true;
	return false;

}
void PatNode::print(ostream& os, int indent) const {
	os << "(";
	switch(kind()) {
	case PRIMITIVE:
		pat1_->print(os,indent);
		break;
	case EMPTY:
		os << "eps";
		break;
	case NEG:
		os << "!";
		if(pat1_)
		pat1_->print(os,indent);
		break;
	case SEQ:
        if(pat1_)
		pat1_->print(os,indent);
		os << ":";
		if(pat2_)
		pat2_->print(os,indent);
		break;
	case OR:
        if(pat1_)
		pat1_->print(os,indent);
		os << " \\/ ";
		if(pat2_)
		pat2_->print(os,indent);
		break;
	case STAR:
        if(pat1_)
		pat1_->print(os,indent);
		os << "**";
		break;
	case UNDEFINED:
		os << "not valid";
		break;
	};
	os << ")";
}

// RuleNode
int RuleNode::ruleInstances_ = 0;
RuleNode::RuleNode(BlockEntry *re,
		BasePatNode* pat, StmtNode* reaction,
		int line, int column, string file) :
	AstNode(AstNode::RULE_NODE, CINFO) {
		rste_ = re;
		pat_ = pat;
		reaction_ = reaction;
		ostringstream os;
		os << "_action_" << ruleInstances_;
		ruleInstances_++;
		func_ = new FunctionEntry(os.str());
		if (reaction && reaction->stmtNodeKind() == StmtNode::COMPOUND)
			func_->body((CompoundStmtNode*)reaction);
		else {
			list<StmtNode*> *comp = new list<StmtNode*>;
			comp->push_back(reaction);
			func_->body(new CompoundStmtNode(comp));
		}
	}

void RuleNode::print(ostream& os, int indent) const {
	if (pat_) {
		prtln(os,indent);
		pat_->print(os,indent);
		os << "-->  ";
	}
	if (reaction_) {
		reaction_->print(os,indent);
	};
	os << ";;";
}

ImmCodes* RuleNode::code(bool controlFlow) {
	return func_->code();
}

// InvocationNode
InvocationNode::InvocationNode(const SymTabEntry *ste, vector<ExprNode*>* param,
		int line, int column, string file) : ExprNode(INV_NODE, NULL, CINFO) {
	params_ = param;
	ste_ = ste;
}

ExprNode* InvocationNode::addr() {
	if (addr_==NULL) {
		addr_=new TempNode();
		// type
		if (ste_->type()) {
			addr_->type((Type*)ste_->type()->retType());
		}
	}
	return (ExprNode*)addr_;
}


InvocationNode::InvocationNode(const InvocationNode& inv) : ExprNode(inv) {
	params_ = inv.params_;
	ste_ = inv.ste_;
}

ImmCodes* InvocationNode::code(bool controlFlow) {
	ImmCodes* c = new ImmCodes();
    FunctionEntry* fe = (FunctionEntry*) ste_;
	//changes for inline
	//VariableEntry * ve=NULL;
	//int var_count = 0;

    /*if(ste) {
		for(SymTab::iterator si =ste->begin(); si!=ste->end(); ++si) {
		    ve=(VariableEntry * )(*si);
            if(ve && ve-> varKind()==VariableEntry:: LOCAL_VAR) {
                    var_count++;
	 		}

		}
    }*/
    //int stmt_count = fe->body()->stmts()->size();
    bool isRetFlag = true;
    if (fe->type() && fe->type()->retType() &&
                    fe->type()->retType()->tag() != Type::VOID) {
                    isRetFlag = false;
    }
    if(!fe->hasRecursion() &&  fe->body()->stmts()->size() <= 5 && isRetFlag) {
        //go for inlining
        SymTab *ste = fe->symTab();
        int param_count = -1;
        if (ste) {
			SymTab::iterator it = ste->begin();
			for (;it!=ste->end();++it) {
				if ( (*it) &&  (*it)->kind() == SymTabEntry::VARIABLE_KIND) {
					VariableEntry* var = (VariableEntry*)(*it);
					if (var && var->varKind() == VariableEntry::PARAM_VAR) {
                        param_count++;
                        //var->initVal((*params_)[param_count]);
                        c->add( ((*params_)[param_count])->code() );
                        RefExprNode* refNode = new RefExprNode(var->name(), var);
                        c->add(ImmCode::EXPR, refNode, ((*params_)[param_count])->addr(),NULL, OpNode::ASSIGN);

					}
					else
					c->add(var->code());
				}
			}
		}
		//get the retunr stmt
		list<StmtNode*>* sm = fe->body()->stmts();
        if(sm){
            list<StmtNode*>::iterator it = sm->begin();
            for (;it!=sm->end();it++) {

            /* propagate Next */
            (*it)->Next(Next());
            if((*it) && (*it)->stmtNodeKind() == StmtNode::RETURN) {
                c->add(((ReturnStmtNode*)(*it))->expr()->code(controlFlow));
                void* retParam = NULL;
                if (fe->type() && fe->type()->retType() &&
                    fe->type()->retType()->tag() != Type::VOID) {
                    retParam = addr();
                }
                //expr_->addr()
                c->add(ImmCode::INLINE,(void*) this, retParam,((ReturnStmtNode*)(*it))->expr()->addr());

		    }
		    else
            c->add((*it)->code(controlFlow));
            }
        }
		//c->add(fe->body()->code());
        return c;
    }
    //changes for inline

	if (params_) {
		vector<ExprNode*>::reverse_iterator it;
		for (it=params_->rbegin();it<params_->rend();++it) {
			c->add((*it)->code(controlFlow));
		}
		for (it=params_->rbegin();it<params_->rend();++it) {
			c->add(ImmCode::PARAM, (*it)->addr(), (void*) this) ;
		}
	}
    fe = (FunctionEntry*) ste_;
	void* retParam = NULL;
	if (fe->type() && fe->type()->retType() &&
			fe->type()->retType()->tag() != Type::VOID) {
		retParam = addr();
	}
	c->add(ImmCode::CALL,(void*) this, retParam);
	return c;
}

void InvocationNode::print(ostream& os, int indent) const {
	os << ste_->name() << "(";
	if (params_) {
		vector<ExprNode*>::const_iterator it;
		for (it=params_->begin(); ;) {
			if (*it) {
				(*it)->print(os, indent);
			}
			++it;
			if (it!=(params_->end())) {
				os << ",";
			} else
				break;
		}
	}
	os << ")";
}

// IfNode

IfNode::IfNode(ExprNode* cond, StmtNode* thenStmt,
		StmtNode* elseStmt, int line, int column, string file) :
	StmtNode(StmtNode::IF, CINFO) {
	cond_ = cond;
	then_ = thenStmt;
	else_ = elseStmt;
}

ImmCodes* IfNode::code(bool controlFlow) {
	ImmCodes* c = new ImmCodes();
	Next(c->newLabel());
	if (!else_) {
		// If (B) S1
		cond_->True(c->newLabel());	// B.true = newLabel()
		cond_->False(Next());		// B.false = S.next
		then_->Next(Next());		// S1.next = S.next
		c->add(cond_->code(true));
		c->add(cond_->True());
		c->add(then_->code());
	} else {
		// If (B) S1 else S2
		cond_->True(c->newLabel());
		cond_->False(c->newLabel());
		then_->Next(Next());
		else_->Next(Next());
		c->add(cond_->code(true));
		c->add(cond_->True());
		c->add(then_->code());
		c->add(ImmCode::GOTO, (void*)Next());	// goto S.next
		c->add(cond_->False());
		c->add(else_->code());
	}
	c->add(Next());
	return c;
}

void IfNode::print(ostream& os, int indent) const {
	os << "if (";
	cond_->print(os,indent);
	os << ") ";
	if (then_) {
		then_->print(os,indent);
		if (then_->stmtNodeKind() != StmtNode::COMPOUND) {
			os << ";";
			if (!else_) prtln(os,indent);
		}
	}
	if (else_) {
		if (then_->stmtNodeKind() != StmtNode::COMPOUND)
			prtln(os, indent);
		os << "else ";
		else_->print(os,indent);
		if (else_->stmtNodeKind() != StmtNode::COMPOUND) {
			os << ";";
			prtln(os, indent);
		}
	}
}

//WhileNode

WhileNode::WhileNode(ExprNode* cond, StmtNode* whileStmt,
		int line, int column, string file) :
	StmtNode(StmtNode::WHILE, CINFO) {
	cond_ = cond;
	stmt_ = whileStmt;
	loop_inv_stmt_ = NULL;
}

ImmCodes* WhileNode::code(bool controlFlow) {
	ImmCodes* c = new ImmCodes();
	//generate code for loop invariant
	if(loop_inv_stmt_) {

	vector<StmtNode*>::iterator its = loop_inv_stmt_->begin();
                        for(;its!=loop_inv_stmt_->end();++its) {
                            //(*its)->print(cout,0);
                            //cout<<endl;
                    c->add((*its)->code());
                        }
	}
	Begin(c->newLabel());
	Next(c->newLabel());
	cond_->True(c->newLabel());
	cond_->False(Next());
	if (stmt_) {
		stmt_->Next(Begin());
	}
	c->add(Begin());
	c->add(cond_->code(true));
	c->add(cond_->True());
	if (stmt_)
		c->add(stmt_->code(false));
	c->add(ImmCode::GOTO, Begin());
	c->add(Next());
	return c;
}

void WhileNode::print(ostream& os, int indent) const {
    os << "while (";
    if(cond())
    cond_->print(os,indent);
    os << ") ";
    if(stmt_) {
        stmt_->print(os,indent);
        if (stmt_->stmtNodeKind() != StmtNode::COMPOUND) {
			os << ";";
			prtln(os, indent);
        }
    }

}

/*void PrintStmtNode::print(ostream& os, int indent) const {
    os << "print(";
    if(cond())
    cond_->print(os,indent);
    os << ");";

}
ImmCodes* PrintStmtNode::code(bool controlFlow) {}*/

ImmCodes* BreakStmtNode::code(bool controlFlow) {
	if (enclosedWhileLoop_ && enclosedWhileLoop_->body()) {
		ImmCode* whileNext = enclosedWhileLoop_->body()->Next();
		ImmCodes* c = new ImmCodes();
		c->add(ImmCode::GOTO, whileNext);
		return c;
	}
	return NULL;
}

void BreakStmtNode::print(ostream& os, int indent) const {
			os << "break ";
			if(loop_num_) loop_num_->print(os,indent);
			os<< ";";
			prtln(os, indent);
}
//added by supreet for event pattern
string PatNode::getEventPattern(string name) const {
	//cout << "(";
	string pat="(";
	string match;
	bool flag;
	int i,j;
	switch(kind()) {
	case PRIMITIVE:
		break;
	case EMPTY:
		break;
	case NEG:
		//cout << "!";
		//pat += "!";
		match ="";
		pat += pat1_->getEventPattern(name);

		for(i=0;i<name.length();i++) {
            flag = true;
            for( j=0;j<pat.length();j++) {
                if(name[i] == pat[j]) {
                    flag = false;
                    break;
                }

            }
            //if(j==pat.length())
            if(flag) {
            match+= "\\/";
            match+= (name[i]) ;

            }
        }

        if(match.length() > 1)
        pat = "(" + match.substr(2);
        else
        //cout<<"match="<<match<<"\n";
        pat = "(" + match;
        //cout<<"\nmatch="<<pat<<"\n";
		break;
	case SEQ:
        pat += pat1_->getEventPattern(name);
		//cout << "|";
		//#ifdef TEST_SUPREET
		pat += ":";
		//#endif
		pat += pat2_->getEventPattern(name);
		break;
	case OR:
		pat += pat1_->getEventPattern(name);
		//cout << "|";
		pat += " \\/ ";
		pat += pat2_->getEventPattern(name);
		break;
	case STAR:
		pat += pat1_->getEventPattern(name);
		//cout << "*";
		pat += "**";
		break;
	case UNDEFINED:
		break;
	};
	//cout << ")";
	pat+=")";
	return pat;
}


string PrimitivePatNode::getEventPattern(string name) const {
	if (!ee_) return "";
    //#ifdef TEST_SUPREET
	//return "(" + ee_->name() + ")";
	//#else
	return ee_->name() ;
	//#endif
}


BasePatNode*
PrimitivePatNode::getComplement(string universe){
	BasePatNode* result;
	EventEntry *ee ;
	int i=0;
	for (;i<universe.length(); i++)
		if (universe.substr(i,1) != this->event()->name()){
		    ee = (EventEntry*)stm.lookUp(universe.substr(i,1));
			//result = new PrimitivePatNode(new EventEntry(universe.substr(i,1)), NULL);
			result = new PrimitivePatNode((ee), NULL);
			break;
		}
	for (i++;i<universe.length(); i++)
		if (universe.substr(i,1) != this->event()->name()){
		    ee = (EventEntry*)stm.lookUp(universe.substr(i,1));
			//result = new PatNode(BasePatNode::OR, result, new PrimitivePatNode(new EventEntry(universe.substr(i,1)), NULL));
			result = new PatNode(BasePatNode::OR, result, new PrimitivePatNode(ee, NULL));
		}

	return result;
}


BasePatNode*
PrimitivePatNode::getComplementForAny(string universe){
	BasePatNode* result;
	EventEntry *ee ;
	if(universe.length() == 0)
        return NULL;
    //ee = (EventEntry*)stm.lookUp(universe.substr(0,1));
    result = new PrimitivePatNode(new EventEntry(universe.substr(0,1)), NULL);
	for (int i=1;i<universe.length(); i++) {
		//if (universe.substr(i,1) != this->event()->name()){
            //ee = (EventEntry*)stm.lookUp(universe.substr(i,1));
			//result = new PatNode(BasePatNode::OR, result, new PrimitivePatNode((ee), NULL));
			//result = new PrimitivePatNode(new EventEntry(universe.substr(i,1)), NULL);
			result = new PatNode(BasePatNode::OR, result, new PrimitivePatNode(new EventEntry(universe.substr(i,1)), NULL));

		//}
	}
	return result;
}



BasePatNode*
PatNode::getComplement(string universe){
	BasePatNode* result;
	EventEntry *ee;
	//Warning: get complement relies on the string representation!!!!!
	string notToInclude = getStringRepresentation();
	cout<<notToInclude;
	size_t found;

	int i=0;
	for (;i<universe.length(); i++)
	{
		found = notToInclude.find(universe.substr(i,1));
		if (found==string::npos){
			//result = new PrimitivePatNode(new EventEntry(universe.substr(i,1)), NULL);
			// event entry look up from symbol table
			ee = (EventEntry*)stm.lookUp(universe.substr(i,1));
			result = new PrimitivePatNode(ee, NULL);
			break;
		}
	}

	for (i++;i<universe.length(); i++)
	{
		found = notToInclude.find(universe.substr(i,1));
		if (found==string::npos){
		    // event entry look up from symbol table
		    ee = (EventEntry*)stm.lookUp(universe.substr(i,1));
			result = new PatNode(BasePatNode::OR, result, new PrimitivePatNode(ee, NULL));
			//result = new PatNode(BasePatNode::OR, result, new PrimitivePatNode(new EventEntry(universe.substr(i,1)), NULL));
			break;
		}
	}

	 return result;
}
string PatNode::replaceNotOperator(string names) const {
    string pat,match;
    bool flag;
    int i,j;
	switch(kind()) {
	case PRIMITIVE:
		break;
	case EMPTY:
		break;
	case NEG:
		//cout << "!";
		//pat += "!";
        match="";

		pat += pat1_->replaceNotOperator(names);
		//cout<<"pat="<<pat<<"\n";
		//cout<<"names="<<names<<"\n";
        for(i=0;i<names.length();i++) {
            flag = true;
            for( j=0;j<pat.length();j++) {
                if(names[i] == pat[j]) {
                    flag = false;
                    break;
                }

            }
            //if(j==pat.length())
            if(flag) {
            match+= "\\/";
            match+= (names[i]) ;

            }
        }
        if(match.length() > 1)
        pat = match.substr(2);
        else
        //cout<<"match="<<match<<"\n";
        pat = match;
        cout<<"\nmatch="<<pat<<"\n";
		break;
	default:
        if(pat1_ )
        pat += pat1_->replaceNotOperator(names);
		//cout << "|";
		//#ifdef TEST_SUPREET
		//pat += ":";
		//#endif
        if(pat2_ )
		pat += pat2_->replaceNotOperator(names);
		//break;
	//case OR:
		//pat += pat1_->replaceNotOperator(names);
		//cout << "|";
		//pat += "|";
		//pat += pat2_->replaceNotOperator(names);
		//break;
	//case STAR:
		//pat += pat1_->replaceNotOperator(names);
		//cout << "*";
		//pat += "*";
		break;
	case UNDEFINED:
		break;
	};
	//cout << ")";
	//pat+=")";
	return pat;

}

string PrimitivePatNode::replaceNotOperator(string name) const {
    return ee_->name() ;
}

